home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
cmln0585.arc
/
BMLP.DOC
< prev
next >
Wrap
Text File
|
1986-02-27
|
58KB
|
1,781 lines
BMLP MACRO LANGUAGE PREPROCESSOR
INTRODUCTION
BMLP and BSLP are preprocessor tools for Microsoft BASIC.
BMLP is a macro language preprocessor. It allows you to write
your programs using macros which you define in the program or
within macro library text files.
BSLP takes a source file containing special structured
statements and translates it into a program containing BASIC
statements.
Using these tools will help you write more concise, better
structured BASIC programs, by allowing you to take advantage
of these features:
- program with macros using parameters and subroutines that
are maintained in libraries where they can be accessed by
all your programs.
- write free-form, indented statements without line numbers.
- include statements from many separate files and libraries
into a single BASIC program. (This lets you write and
maintain your programs in small modules.)
- organize your subroutines into procedures, each with its
own descriptive alpha-numeric name.
- structure your programming with multi-line conditionals,
loop and case constructs similar to those found in
programming languages like C and Pascal.
When using these preprocessors, please bear in mind that
these versions are written in BASIC and are provided for your
use and you are free to modify them in any manner you see fit.
If you find these tools useful, we have a package called PPE
(Professional Programming Environment) that includes a super
preprocessor (SLPC) which is written in C for faster
processing (300-400 lines/min). It does everything that
these do PLUS a lot more, like providing a define statement
for text substitution and built-in random file handling macro
statements. It comes with a large library of macros and a
library manager program.
If you have suggestions, questions, comments or would like
more information about the PPE package,
please contact us at:è
Bendorf Associates
P.O. Box 5910
6006 S. Main
Roswell, NM 88201
(505) 347-5701
The following is a list and brief abstract of the files on
this disk:
Files for BSLP: Basic Structured Language Preprocessor
BSLP.P . . . . . . . Structured Language Source Text
BSLP.BAS . . . . . . Microsoft Basic Source Code
BSLP.DOC . . . . . . Documentation
BSLP.MSD . . . . . . MS-DOS Compiled Version (.EXE)
BSLP.CPM . . . . . . CP/M 80 Compiled Version (.COM)
Files for BMLP: Basic Macro Language Preprocessor
BMLP.P . . . . . . . Structured Language Source Text
BMLP.BAS . . . . . . Microsoft Basic Source Code
BMLP.DOC . . . . . . Documentation
BMLP.MSD . . . . . . MS-DOS Compiled Version (.EXE)
BMLP.CPM . . . . . . CP/M 80 Compiled Version (.COM)
Files for BSLP & BMLP example programs
XFRAME.M . . . . . . Example Program Source Text
XFRAME.ML . . . . . Library for XFRAME.M
BINPUT.M . . . . . . Example Program Source Text
BINPUT.ML . . . . . Library for BINPUT.M
BMLP.DOC
Function
BMLP expands macro expressions using program resident and/or
library file macro definitions. BMLP is written in 'SSS'
language and should be a useful learning tool.
Invocation
Entering 'BMLP' at the DOS prompt will envoke the compiled
version (.EXE) of BMLP. The (.BAS) version will have to be
run using the interpreter by entering 'BASICA BMLP' at the
DOS prompt. BMLP will then prompt for the input file name
and the output file name. The default for the input file
extension is '.M', and the default for the output file name
is the input file name with the extension of '.P'.
Formats è
Macro expression format:
$macro-name param1,param2,param3
A leading dollar sign ($) is used to identify a macro name
and, except for spaces and tabs, must be the first character
on the line. When parameters are used, they must be
separated by a comma, tab, or space; when there are too many
to put on one line, a double backslash (\\) may be used to
continue on the next line.
Macro coding format:
MACRO <macro-name>
ENDM
Macros are written and maintained with a text editor in one
or more library text files and/or program source files.
Macro names may contain any combination of characters except
commas, tabs, and spaces, and there is no case
discrimination. The keyword 'MACRO' is used to identify a
macro name and the beginning of code for that macro name.
The keyword 'ENDM' identifies the end of code for a macro
name. Within the macro code a number enclosed with brackets
([]) identifies a parameter request. A leading semi-colon
(;) may be used as a comment character. Macros may use other
macros as well as supporting subroutines (more on this
later).
Design
Writing macros is easy, fun and can be habit forming once you
get the hang of it. To demonstrate let's take the simple
task of displaying text on the video monitor. The following
list of operations describes this task in detail:
1. Save the current cursor location.
2. Turn off and re-position the cursor.
3. Clear a space the size of the text.
4. Re-position the cursor.
5. Display the text.
6. Restore cursor location and turn it on.
BASIC code for this example might be:
100 XR%=CSRLIN:XC%=POS(0)
:LOCATE,,0:LOCATE ROW,COL
:PRINT SPACE$(LEN(TEXT$));
:LOCATE ROW,COL
:PRINT TEXT$;
:LOCATE XR%,XC%,1
A macro expression for the above example:
$CRT ROW,COL,TEXT$
/--- -------------\
Macro Name Parameter List
Code for the 'CRT' macro could be written like this:
MACRO CRT
XR%=CSRLIN:XC%=POS(0)
LOCATE,,0:LOCATE [1],[2],0:PRINT SPACE$(LEN([3]));
LOCATE [1],[2],0:PRINT [3];:LOCATE XR%,XC%,1
ENDM
The parameters are numbered in left to right order as they
appear in the list following the 'CRT' macro, e.g.;
[1] = ROW <parameter one>
[2] = COL <parameter two>
[3] = TEXT$ <parameter three>
Parameters can be passed using variables or literal
expressions:
$CRT 12,10,"Hello World!"
Nesting Macros
Because a macro can use other macros (nesting), the 'CRT'
macro can also be written using macros for the required six
functions.
1. Save the current cursor location. ------+
| MACRO SVC |
| [1]=CSRLIN:[2]=POS(0) |
| ENDM |
+------------------------------------------+
2. Position the cursor and switch on/off. -+
| MACRO XY |
| LOCATE [1],[2],[3] |
| ENDM |
+------------------------------------------+
3. Clear a space the size of the text. ----+
| MACRO CLR |
| PRINT SPACE$([1]); |
| ENDM |
+------------------------------------------+
4. Re-position the cursor. ----------------+
| (Use the XY macro, (2)) |
+------------------------------------------+
5. Display the text. ----------------------+
| MACRO SHO |
| PRINT [1]; |
| ENDM |
+------------------------------------------+
6. Restore cursor location, turn it on. ---+
| (Again use the XY macro, (2)) |è +------------------------------------------+
Now the 'CRT' macro can be written using the four new macros:
MACRO CRT
$SVC XR%,XC%
$XY ,,0
$XY [1],[2],0
$CLR LEN([3])
$XY [1],[2],0
$SHO [3]
$XY XR%,XC%,1
ENDM
Writing macros for the lower level functions of the 'CRT'
macro provides several benefits, one of them being the
availability of lower level macros to be used in writing
other higher level macros.
Conditional Logic
$IF / $ELSE / $END
'$IF-$ELSE-$END' are reserved macro keywords that provide the
ability to control the inclusion or expansion of segments of
code within a macro. The 'CRT' macro can be enhanced with
added ability to display the text in reverse video. This is
easily implemented using a fourth parameter and conditional
logic to control the inclusion of the "COLOR" statement.
MACRO CRT
$SVC XR%,XC%
$XY ,,0
$XY [1],[2],0
$CLR LEN([3])
$XY [1],[2],0
$IF [4] <--+ If fourth parameter ([4]) is provided
COLOR 0,7 | then the statement 'COLOR 0,7' will
$END <--+ be included. (Reverse)
$SHO [3]
$IF [4] <--+ If fourth parameter ([4]) is provided
COLOR 7,0 | then the statement 'COLOR 7,0' will
$END <--+ be included. (Reset to Normal)
$XY XR%,XC%,1
ENDM
Example:
$CRT 12,10,"Hello World!",REV
\..(fourth parameter)
(Display "Hello World!" at row 12, column 10, in reverse video.)
$CRT 12,10,"Hello World!"
\..(missing fourth parameter)
(Display "Hello World!" at row 12, column 10, in normal video.)
Logical Operators
The 'equal-to (=)' and the 'not-equal (#) or (<>)' logical
operators can be used to test literal parameters for a
specific value, e.g.;
$IF [1] = 1
$IF [6] # NOERROR
$IF [4] = REV
\
(Operators must to be separated by spaces or tabs.)
'CRT' macro with logical operators:
MACRO CRT
$SVC XR%,XC%
$XY ,,0
$XY [1],[2],0
$CLR LEN([3])
$XY [1],[2],0
$IF [4] = REV <--+ If fourth parameter ([4]) EQUALS "REV"
COLOR 0,7 | then the statement 'COLOR 0,7' will
$END <--+ be included. (Reverse)
$SHO [3]
$IF [4] # NORM <--+ If fourth parameter ([4]) NOT EQUAL "NORM"
COLOR 7,0 | then the statement 'COLOR 7,0' will
$END <--+ be included. (Reset to Normal)
$XY XR%,XC%,1
ENDM
Example:
$CRT 12,10,"Hello World!",REV
\..(fourth parameter)
(Display "Hello World!" at row 12, column 10, in reverse video.)
$CRT 12,10,"Hello World!",NORM
\..(fourth parameter)
(Display "Hello World!" at row 12, column 10, in normal video.)
Macros and Subroutines
One of the more powerful features of macro programming is the
ability to write macros that require supporting subroutines.
This ability allows the use of a macro any number of times
within a program, with only one inclusion of its supporting
subroutine. Thus, blocks of duplicated code are eliminated.
An example is the operation of stripping leading and trailing
space and tab characters from a string of text:
$STRIP TEXT$
The code for 'STRIP' macro:------+
MACRO STRIP |
X$=[1]:Gosub _Stripit:[1]=X$ |
$$_STRIP |
ENDM |
---------------------------------+
The code for '_STRIP' supporting subroutine:----------------+
MACRO _STRIP |
proc _Stripit |
unless LEN(X$)<3 |
X%=LEN(X$)+1 |
WHILE(X%>LEN(X$) AND LEN(X$)>2) |
X%=LEN(X$) |
X$=LEFT$(X$,LEN(X$)+(RIGHT$(X$,1)=" ")) |
X$=LEFT$(X$,LEN(X$)+(ASC(RIGHT$(X$,1))=9)) |
X$=RIGHT$(X$,LEN(X$)+(ASC(X$)=32 OR ASC(X$)=9)) |
WEND |
endu |
endp |
ENDM |
------------------------------------------------------------+
The leading double dollar sign ($$) identify '_STRIP' as a
subroutine which is defined as a procedure (_Stripit) and it
will be included into a program source file only one time. A
subroutine may include and use other subroutines and macros.
Developing Libraries
Macros can be written within a program source file, where
they can be easily tested and debugged before being committed
to a library file. Library documentation is extremely
important. After writing a couple of dozen macros, it
becomes a little more difficult to remember function and
parameter requirements for each macro. The ability to share
libraries among several programmers working on the same
project makes the library documentation essential.
Using Libraries
LIBRARY <file-name.ext>
The keyword 'LIBRARY' is used at the top of a program source
file to identify each macro library to use in processing that
source file. Libraries can be nested by specifing libraries
within libraries.
BMLP.BAS
100 SIGN$ = "$"
101 DOT$ = "."
102 OEXT$ = ".P" ' Output file default extension
103 IEXT$ = ".M" ' Input file default extension
104 LEXT$ = ".ML" ' Library file default extension
105 SOURCE% = 2 ' Input file number
106 O.FILE% = 1 ' Output file number
107 I.FILE% = 2
108 ERRORS% = 0
109 FALSE% = 0
110 TRUE% = NOT FALSE%
111 EXPAND% = TRUE%
112 STORE.% = 0
113 NEST% = 1
114 DIM FILE.%(50) ' TEMPORARY STACK OF POINTERS TO THE NEXT SUBSCRIPT
115 DIM PARM$(500) ' TEMPORARY STORAGE OF PARAMETERS TO PASS TO MACROS.
116 DIM PARM%(100) ' ARRAY OF POINTERS TO PARAMETER STORAGE.
117 DIM MACRO$(100) ' STORAGE FOR MACRO NAMES.
118 DIM MACRO%(100) ' ARRAY OF POINTERS TO FIRST CODE LOCATION IN STORE$ ARRAY
119 DIM STORE$(1000) ' STORAGE FOR MACRO TEXT.
120 DIM SUBS$(50) ' STORAGE FOR MACRO SUBROUTINE NAMES.
121 PRINT "BMLP V1.0B (C) BENDORF ASSOCIATES, 1984-85"
122 PRINT
123 GoSub 354
124 IF NOT(I.FILE%>0) GOTO 133
125 GoSub 137
126 CLOSE
127 IF NOT(ERRORS%>0) GOTO 131
128 KILL O.FILE$è129 PRINT O.FILE$;" ABORTED WITH ";STR$(ERRORS%);" ERROR(S)."
130 GOTO 132
131 PRINT"<";O.FILE$;"> DONE!"
132 GOTO 135
133 IF NOT(I.FILE$<>"") GOTO 135
134 PRINT"CANNOT OPEN ";I.FILE$
135 END
136 'PROCESS-SOURCE-FILE
137 OPEN"O",O.FILE%,O.FILE$
138 OPEN"I",I.FILE%,I.FILE$
139 FILE.%(NEST%)=-1
140 IF(NEST%=0) GOTO 175
141 while ENDOFF%=FALSE%
142 GoSub 267
143 IF NOT(LN.%>1 AND ENDOFF%=FALSE%) GOTO 147
144 GoSub 207
145 GoSub 177
146 GOTO 149
147 IF NOT(SKIP% AND I.FILE%=SOURCE%) GOTO 149
148 PRINT #O.FILE%,BUF$
149 wend
150 IF(NEST%=1)THEN FIRST%=0 ELSE FIRST%=PARM%(NEST%-1)
151 LAST%=PARM%(NEST%)
152 PARM%(NEST%)=0
153 while (FIRST%<LAST%)
154 PARM$(LAST%)=""
155 LAST%=LAST%-1
156 wend
157 IF NOT(FILE.%(NEST%)<0 AND NEST%>1 AND I.FILE%>SOURCE%) GOTO 161
158 CLOSE #I.FILE%
159 I.FILE%=I.FILE%-1
160 GOTO 162
161 POINTER%=FILE.%(NEST%-1)
162 NEST%=NEST%-1
163 ENDOFF%=FALSE%
164 IF(NEST%>0 OR SUBS%=LAST.S%) GOTO 174
165 LAST.S%=LAST.S%+1
166 TEXT$=SUBS$(LAST.S%)
167 GoSub 301
168 IF NOT(FOUND%) GOTO 172
169 FILE.%(NEST%+1)=FIND%:POINTER%=FIND%
170 NEST%=NEST%+1
171 GOTO 174
172 EBUF$="SUBROUTINE ("+TEXT$+") NOT FOUND!"
173 GoSub 367
174 IF(NEST%>0) GOTO 140
175 RETURN
176 'PARSE-INPUT-LINE
177 GoSub 334
178 GoSub 372
179 IF NOT(LEFT$(TEXT$,1)=SIGN$) GOTO 197
180 TEXT$=RIGHT$(TEXT$,LEN(TEXT$)-1)
181 IF NOT(TEXT$="if") GOTO 184
182 GoSub 220
183 GOTO 196è184 IF NOT(TEXT$="else") GOTO 187
185 EXPAND%=(EXPAND%=FALSE%)
186 GOTO 196
187 IF NOT(TEXT$="end") GOTO 190
188 EXPAND%=TRUE%
189 GOTO 196
190 IF NOT(LEFT$(TEXT$,1)=SIGN$) GOTO 194
191 TEXT$=RIGHT$(TEXT$,LEN(TEXT$)-1)
192 GoSub 395
193 GOTO 196
194 IF NOT(EXPAND%) GOTO 196
195 GoSub 241
196 GOTO 205
197 IF NOT(TEXT$="macro") GOTO 200
198 GoSub 309
199 GOTO 205
200 IF NOT(TEXT$="library") GOTO 203
201 GoSub 379
202 GOTO 205
203 IF NOT(EXPAND% AND I.FILE%=SOURCE%) GOTO 205
204 PRINT #O.FILE%,BUF$
205 RETURN
206 'INSERT-PARAMETERS
207 LB%=INSTR(1,BUF$,"[")
208 while (LB%>0)
209 RB%=INSTR(LB%,BUF$,"]")
210 IF NOT(RB%>0) GOTO 215
211 INSERT$=PARM$(PARM%(NEST%-1)+VAL(MID$(BUF$,LB%+1,RB%-LB%)))
212 BUF$=LEFT$(BUF$,LB%-1)+INSERT$+RIGHT$(BUF$,LEN(BUF$)-RB%)
213 LB%=INSTR(RB%,BUF$,"[")
214 GOTO 216
215 LB%=0
216 wend
217 LN.%=LEN(BUF$)
218 RETURN
219 'SET-CONDITIONAL
220 GoSub 334
221 L$=TEXT$:OP$=""
222 IF(L$="=" OR L$="#" OR L$="<>")THEN OP$=L$:L$=""
223 GoSub 334
224 IF NOT(TEXT$="") GOTO 227
225 OP$="<>":R$=""
226 GOTO 231
227 IF NOT(OP$="") GOTO 231
228 OP$=TEXT$
229 GoSub 334
230 R$=TEXT$
231 IF NOT(OP$="=") GOTO 234
232 EXPAND%=(R$=L$)
233 GOTO 239
234 IF NOT(OP$="<>" OR OP$="#") GOTO 237
235 EXPAND%=(R$<>L$)
236 GOTO 239
237 EBUF$="ILLEGAL OPERATOR("+OP$+")"
238 GoSub 367è239 RETURN
240 'EXPAND-MACRO
241 GoSub 301
242 IF NOT(FOUND%) GOTO 250
243 IF(FILE.%(NEST%)=>0)THEN FILE.%(NEST%)=POINTER%
244 POINTER%=FIND%
245 NEST%=NEST%+1
246 FILE.%(NEST%)=FIND%
247 PARM%(NEST%)=PARM%(NEST%-1)
248 GoSub 254
249 GOTO 252
250 EBUF$="MACRO ("+TEXT$+") NOT DEFINED."
251 GoSub 367
252 RETURN
253 'LOAD-PARAMETERS
254 PASS%=FALSE%
255 while PASS%=FALSE%
256 PASS%=(CON%=FALSE%)
257 GoSub 334
258 while (FIRST%<=LN.%)
259 PARM%(NEST%)=PARM%(NEST%)+1
260 PARM$(PARM%(NEST%))=TEXT$
261 GoSub 334
262 wend
263 IF(CON%)THEN GoSub 279
264 wend
265 RETURN
266 'INPUT-BUFFER
267 IF NOT(FILE.%(NEST%)<0) GOTO 270
268 GoSub 279
269 GOTO 277
270 BUF$=STORE$(POINTER%)
271 POINTER%=POINTER%+1
272 ENDOFF%=(BUF$=CHR$(7))
273 SKIP%=FALSE%
274 CON%=SKIP%
275 LN.%=LEN(BUF$)
276 INDEX%=0
277 RETURN
278 'INPUT-SOURCE
279 INDEX%=0:CON%=FALSE%
280 LINE INPUT #I.FILE%,BUF$
281 ENDOFF%=EOF(I.FILE%)
282 LN.%=LEN(BUF$):I%=1:II%=0
283 while (I%>II% AND I%<LEN(BUF$))
284 II%=I%:I%=I%+ABS(MID$(BUF$,I%,1)=" " OR MID$(BUF$,I%,1)=CHR$(9))
285 wend
286 II%=LN.%+1
287 while (II%>LN.% AND LN.%>I%)
288 II%=LN.%:LN.%=LN.%+(MID$(BUF$,LN.%,1)=" " OR MID$(BUF$,LN.%,1)=CHR$(9))
289 wend
290 BUF$=MID$(BUF$,I%,LN.%):LN.%=LEN(BUF$)
291 SKIP%=(MID$(BUF$,1,1)="'" OR MID$(BUF$,1,1)=";" OR LEN(BUF$)<2)
292 IF NOT(SKIP%) GOTO 295
293 LN.%=1è294 GOTO 299
295 IF NOT(RIGHT$(BUF$,2)="\\") GOTO 299
296 CON%=TRUE%
297 BUF$=LEFT$(BUF$,LEN(BUF$)-2)
298 LN.%=LEN(BUF$)
299 RETURN
300 'FIND-MACRO-NAME
301 FIND%=FALSE%:THIS.M%=0
302 FOR M%=1 TO LAST.M%
303 IF(MACRO$(M%)=TEXT$)THEN THIS.M%=M%:M%=LAST.M%+1
304 NEXT M%
305 FOUND%=(THIS.M%>0)
306 IF(FOUND%)THEN FIND%=MACRO%(THIS.M%)
307 RETURN
308 'INPUT-A-MACRO
309 GoSub 334
310 GoSub 372
311 GoSub 301
312 IF NOT(FOUND%) GOTO 315
313 MACRO%(THIS.M%)=STORE.%+1
314 GOTO 318
315 MACRO$(LAST.M%+1)=TEXT$
316 MACRO%(LAST.M%+1)=STORE.%+1
317 LAST.M%=LAST.M%+1
318 GoSub 279
319 GoSub 334
320 GoSub 372
321 while (TEXT$<>"endm" AND ENDOFF%=FALSE%)
322 IF(SKIP%=FALSE%)THEN GoSub 330
323 GoSub 279
324 IF(SKIP%=FALSE%)THEN GoSub 334:GoSub 372
325 wend
326 BUF$=CHR$(7)
327 GoSub 330
328 RETURN
329 'STORE-MACRO-CODE
330 STORE.%=STORE.%+1
331 STORE$(STORE.%)=BUF$
332 RETURN
333 'PARSER
334 I%=32
335 while (I%=32)
336 INDEX%=INDEX%+1
337 IF(INDEX%<=LEN(BUF$))THEN I%=ASC(MID$(BUF$,INDEX%,1)) ELSE I%=7
338 I%=I%+(23*ABS(I%=9))
339 wend
340 FIRST%=INDEX%
341 while (I%<>32 AND I%<>7)
342 IF NOT(I%=44 OR I%=9) GOTO 345
343 I%=32
344 GOTO 350
345 IF NOT(I%=34) GOTO 348
346 X%=INSTR(INDEX%+1,BUF$,CHR$(34))
347 IF(X%>INDEX%)THEN INDEX%=X%
348 INDEX%=INDEX%+1è349 IF(INDEX%<=LEN(BUF$))THEN I%=ASC(MID$(BUF$,INDEX%,1)) ELSE I%=7
350 wend
351 TEXT$=MID$(BUF$,FIRST%,INDEX%-FIRST%)
352 RETURN
353 'FILENAMES
354 LINE INPUT"INPUT FILE [.M]:",I.FILE$
355 IF(I.FILE$="") GOTO 365
356 IF(INSTR(I.FILE$,DOT$)=0)THEN I.FILE$=I.FILE$+IEXT$
357 LK.$=I.FILE$:LK.%=I.FILE%:GoSub 391:I.FILE%=LK.%
358 IF(I.FILE%=FALSE%) GOTO 365
359 I%=INSTR(1,I.FILE$,DOT$)
360 IF(I%=0)THEN I%=LEN(I.FILE$)+1
361 FILE$=LEFT$(I.FILE$,I%-1)
362 LINE INPUT"OUTPUT FILE [.P]:",O.FILE$
363 IF(O.FILE$="")THEN O.FILE$=FILE$
364 IF(INSTR(O.FILE$,DOT$)=0)THEN O.FILE$=O.FILE$+OEXT$
365 RETURN
366 'ERRORS
367 ERRORS%=ERRORS%+1
368 EBUF$="ERR#"+STR$(ERRORS%)+" ("+EBUF$+")"
369 PRINT EBUF$
370 RETURN
371 'LCASE
372 I%=1
373 while (I%<=LEN(TEXT$))
374 II%=ASC(MID$(TEXT$,I%,1))
375 MID$(TEXT$,I%,1)=CHR$(II%+(32*ABS(II%>64 AND II%<91))):I%=I%+1
376 wend
377 RETURN
378 'LIBRARY
379 GoSub 334
380 IF(TEXT$="") GOTO 389
381 IF(INSTR(TEXT$,DOT$)=0)THEN TEXT$=TEXT$+LEXT$
382 LK.%=I.FILE%+1:LK.$=TEXT$:GoSub 391
383 IF NOT(LK.%>0) GOTO 387
384 OPEN"I",LK.%,LK.$:I.FILE%=LK.%
385 NEST%=NEST%+1:FILE.%(NEST%)=-1
386 GOTO 389
387 EBUF$="LIBRARY ("+LK.$+") NOT FOUND!"
388 GoSub 367
389 RETURN
390 '_Lookup
391 OPEN"R",LK.%,LK.$:L.K!=LOF(LK.%):CLOSE LK.%
392 IF(L.K!<1)THEN LK.%=0:KILL LK.$
393 RETURN
394 'SUBROUTINE
395 S%=0
396 while (S%<SUBS%)
397 S%=S%+1:IF(TEXT$=SUBS$(S%))THEN S%=SUBS%+1
398 wend
399 IF(S%=SUBS%)THEN SUBS%=SUBS%+1:SUBS$(SUBS%)=TEXT$
400 RETURN